﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Security.Principal;
using System.Diagnostics;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using SAKS.Models;
using SAKS.ViewModels;
using SAKS.IServices;
using SAKS.Services;
using SAKS.ActionFilters;
using AutoMapper;
using log4net;
using log4net.Repository.Hierarchy;


namespace SAKS.Controllers
{
    [Authorize]
    [NeedsPersistence]
    public class ProjectController : ControllerBase
    {
        public IProjectServices ProjectServices { get; set; }
        public IMessageServices MessageServices { get; set; }
        public IPictureServices PictureServices { get; set; }
        public IDocumentServices DocumentServices { get; set; }
        public ISearchServices SearchServices { get; set; }
        public IReportServices ReportServices { get; set; }


        protected override void Initialize(RequestContext requestContext)
        {
            base.Initialize(requestContext);
            var session = GetCurrentSession(requestContext);
            MessageServices.Session = session;
            ProjectServices.Session = session;
            PictureServices.Session = session;
            DocumentServices.Session = session;
            SearchServices.Session = session;
            ReportServices = new ReportServices();
            ReportServices.Session = session;
        }

        public ActionResult Index()
        {
            return View();
        }

        #region Json


        public ActionResult List(DataTableParameter param)
        {
            int? _start = param.iDisplayStart;
            int? _pageSize = param.iDisplayLength;
            int first = _start ?? 0;
            int pageSize = _pageSize ?? 20;
            int? totalRecords = new int?();
            var ret = ProjectServices.List(first, pageSize, out totalRecords, param.sSearch);
            var json = BuildJsonResult(param, totalRecords, ret);
            return json;
        }

        public ActionResult Member(Guid projectid, string p304)
        {
            if (IsUserInProject(projectid) || HttpContext.User.IsInRole("Superviser"))
            {
                var members = ProjectServices.GetMembers(projectid);
                var membernames = from n in members select n.UserName;
                return Json(new AjaxResponse { Data = membernames, State = "Succeed" }, JsonRequestBehavior.AllowGet);
            }
            else
            {
                return Json(new AjaxResponse { Message = "只有项目成员可以查看此内容", State = "Failure" }, JsonRequestBehavior.AllowGet);
            }
        }
        [HttpPost]
        public ActionResult RemoveUser(string username, Guid projectId)
        {
            var admin = GetProjectAdmin(projectId);
            if (admin == HttpContext.User.Identity.Name)
            {
                if (admin == username)
                {
                    return Json(new { Message = "移除失败 - 管理员无法移除自己，请先任命新的管理员", State = "Failure" });
                }
                else
                {
                    ProjectServices.RemoveMember(username, projectId);
                    UpdateCache_IsUserInProject(username, projectId, false);
                    MessageServices.SendRemovedFromProjectMessage(username, projectId);
                    return Json(new { Message = "移除成功", State = "Succeed" });
                }
            }
            else
            {
                return Json(new { Message = "移除失败 - 只有管理员可以移除成员", State = "Failure" });
            }
        }

        private JsonResult BuildJsonResult(DataTableParameter param, int? totalRecords, object[] ret)
        {
            var json = Json(
                new dataTableJson
                {
                    sEcho = param.sEcho,
                    iTotalRecords = totalRecords,
                    iTotalDisplayRecords = totalRecords,
                    aaData = ret
                },
                JsonRequestBehavior.AllowGet
            );
            return json;
        }

        #endregion

        #region Create

        public ActionResult Create()
        {
            return View(new ProjectCreateUpdateModel());
        }

        [HttpPost]
        public ActionResult Create(ProjectCreateUpdateModel model)
        {
            if (ModelState.IsValid)
            {
                var admin = HttpContext.User.Identity.Name;
                CreateStatus status = ProjectServices.Create(ProjectMapper.ToProject(model), admin);
                if (status == CreateStatus.Succeed)
                {
                    return RedirectToAction("Index");
                }
                else
                {
                    ModelState.AddModelError("CreateFailure", "创建失败");
                    return View(model);
                }
            }
            else
            {
                ModelState.AddModelError("CreateFailure", "创建失败");
                return View(model);
            }
        }
        #endregion

        #region Pages
        public ActionResult UploadReport(Guid id)
        {
            Init(id);
            return View(new ReportCreateUpdateModel());
        }
        [HttpPost]
        public ActionResult UploadReport(ReportCreateUpdateModel model)
        {
            var id = (Guid)model.ProjectId;
            Init(id);
            if (ModelState.IsValid)
            {
                HttpPostedFileBase doc = Request.Files["doc"];
                var dotindex = doc.FileName.LastIndexOf('.');
                var i = doc.FileName.LastIndexOf('/');
                var j = doc.FileName.LastIndexOf('\\');
                var sindex = i > j ? i + 1 : j + 1;
                var doctype = doc.FileName.Substring(dotindex, doc.FileName.Length - dotindex);
                var docname = doc.FileName.Substring(sindex, doc.FileName.Length - sindex);
                byte[] buf = new byte[doc.ContentLength];
                doc.InputStream.Read(buf, 0, doc.ContentLength);
                var reportfile = new ConferenceReportFile() { Doc = buf, Type = doctype, ProjectId = id, Name = docname };
                var info = ReportMapper.ToReportInfo(model);
                info.ReportFile = reportfile;
                reportfile.ReportInfo = info;
                info.CreatedDate = DateTime.Now;
                info.ReportName = docname;
                var fileId = ReportServices.SaveFile(reportfile);
                info.FileId = fileId;
                ReportServices.SaveInfo(info);
                return RedirectToAction("ReportList", new { Id = model.ProjectId });
            }
            else
                return View(model);
        }
        public ActionResult UploadDoc(Guid id)
        {
            Init(id);
            return View(new DocumentCreateUpdateModel());
        }
        [HttpPost]
        public ActionResult UploadDoc(DocumentCreateUpdateModel model)
        {
            var id = (Guid)model.ProjectId;
            Init(id);
            if (ModelState.IsValid)
            {
                              
                HttpPostedFileBase doc = Request.Files["doc"];
                var dotindex = doc.FileName.LastIndexOf('.');
                var i = doc.FileName.LastIndexOf('/');
                var j = doc.FileName.LastIndexOf('\\');
                var sindex = i > j ? i + 1 : j + 1;
                var doctype = doc.FileName.Substring(dotindex, doc.FileName.Length - dotindex);
                var docname = doc.FileName.Substring(sindex, doc.FileName.Length - sindex);
                byte[] buf = new byte[doc.ContentLength];
                doc.InputStream.Read(buf, 0, doc.ContentLength);
                var docfile = new DocFile() { Doc = buf, Type = doctype, ProjectId = id, Name = docname};
                var info = DocumentMapper.ToDocumentInfo(model);
                info.DocFile = docfile;
                docfile.DocumentInfo = info;              
                info.CreatedDate = DateTime.Now;
                info.Name = docname;
                var fileId = DocumentServices.SaveFile(docfile);
                info.FileId = fileId;
                DocumentServices.SaveInfo(info);
                return RedirectToAction("DocumentList", new { Id = model.ProjectId });
            }
            else
                return View(model);
        }
        public ActionResult UploadPicture(Guid id)
        {
            Init(id);
            return View();
        }
        

        [HttpPost]
        public ActionResult UploadPicture(PictureInfo pic, Guid projectId)
        {
            Init(projectId);

            if (string.IsNullOrEmpty(pic.Name))
            {
                ModelState.AddModelError("", "图件名称必须填写");
                return View();
            }

            HttpPostedFileBase image = Request.Files["image"];
            if (image.ContentLength == 0)
            {
                ModelState.AddModelError("", "请选择一个图片上传");
                return View();
            }
            byte[] imagebuf = new byte[image.ContentLength];
            image.InputStream.Read(imagebuf, 0, image.ContentLength);
            var picid = PictureServices.SavePictureFile(imagebuf);
            
            pic.PictureId = picid;
            pic.ProjectId = projectId;
            PictureServices.SavePictureInfo(pic);
            return RedirectToAction("PictureList", new { id = projectId });

        }
        public ActionResult PictureList(Guid id,int? page)
        {
            Init(id);
            int pageSize = 10;
            int _page = page == null ? 0 : (int)page;
            int start = pageSize * _page;
            int? totalRecords;
            var list = PictureServices.GetInfoList(id, start, pageSize, out totalRecords);
            int totalPages = (int)Math.Ceiling((double)totalRecords / (double)pageSize);
            ViewBag.NextPage = totalPages > _page ? _page + 1 : -1;
            ViewBag.PrePage = 0 < _page ? _page - 1 : -1;
            return View(list);
        }
        public ActionResult DocumentList(Guid id, int? page,string key)
        {
            Init(id);
            int pageSize = 5;
            int _page = page == null ? 0 : (int)page;
            int start = pageSize * _page;
            int? totalRecords;
            IEnumerable<DocumentInfo> list;
            if (string.IsNullOrEmpty(key))
            {
                list = DocumentServices.GetProDocInfoList(id, start, pageSize, out totalRecords);
            }
            else
            {
                list = SearchServices.ProDocSearch(id, start, pageSize, out totalRecords, key);
                ViewBag.Key = key;
            }

            int totalPages = (int)Math.Ceiling((double)totalRecords / (double)pageSize);
            ViewBag.NextPage = totalPages-1 > _page ? _page + 1 : -1;
            ViewBag.PrePage = 0 < _page ? _page - 1 : -1;
            ViewBag.UploadAction = "UploadDoc";
            return View(list);
        }
        public ActionResult ReportList(Guid? id, int? page, string key)
        {
            Guid _id = (Guid)id;
            Init(_id);
            int pageSize = 20;
            int _page = page == null ? 0 : (int)page;
            int start = pageSize * _page;
            int? totalRecords;
            IEnumerable<ConferenceReportInfo> list;
            if (string.IsNullOrEmpty(key))
            {
                list = ReportServices.GetReportInfoList(_id, start, pageSize, out totalRecords);
            }
            else
            {
                list = SearchServices.ReportSearch(_id, start, pageSize, out totalRecords, key);
                ViewBag.Key = key;
            }

            int totalPages = (int)Math.Ceiling((double)totalRecords / (double)pageSize);
            ViewBag.NextPage = totalPages - 1 > _page ? _page + 1 : -1;
            ViewBag.PrePage = 0 < _page ? _page - 1 : -1;
            ViewBag.UploadAction = "UploadReport";
            return View(list);
        }

        public ActionResult MemberManage(Guid id)
        {
            Init(id);
            return View(ProjectServices.GetMembers(id));
        }



        public ActionResult Process(Guid id)
        {
            Init(id);
            var list = ProjectServices.GetProcess(id);
            return View(list);
        }
        public ActionResult AddProcess(Guid id)
        {
            Init(id);
            return View();
        }
        [HttpPost]
        public ActionResult AddProcess(Guid projectId,ProjectProcess process)
        {
            Init(projectId);
            ProjectServices.AddProcess(projectId, process);
            return RedirectToAction("Process", new { Id = projectId });
        }
        [HttpPost]
        public ActionResult RemoveProcess(Guid projectId,Guid processId)
        {
            ProjectServices.RemoveProcess(projectId, processId);
            return Json(new { ProcessId = processId });
        }
        public ActionResult Details(Guid id)
        {
            try
            {
                Init(id);
                var model = ProjectMapper.ToDetailsModel(ProjectServices.GetProjectById(id));
                return View(model);
            }
            catch (Exception )
            {
                return RedirectToAction("Error");
            }           
        }

        public ActionResult Edit(Guid id)
        {
            try
            {
                Init(id);
                var model = ProjectMapper.ToCreateUpdateModel(ProjectServices.GetProjectById(id));
                return View(model);
            }
            catch (Exception e)
            {
                ViewBag.ErrorMessage = e.Message;
                return RedirectToAction("Error");
            }  
        }
        [HttpPost]
        public ActionResult Edit(ProjectCreateUpdateModel model)
        {
            ProjectServices.UpdateProjectInfo(model);
            UpdateCache_ProjectAdmin(model.Name, model.Id);
            return RedirectToAction("Details", new { Id = model.Id });
        }

        public ActionResult Supervise(Guid Id)
        {
            Init(Id);
            ViewBag.ProjectName = ProjectServices.GetProjectNameById(Id);
            var newprocess = ProjectServices.GetNewestProcess(Id);

            return View(newprocess);
        }
        [HttpPost]
        public ActionResult Supervise(Guid ProjectId, Guid ProcessId)
        {
            Init(ProjectId);
            ProjectServices.ApproveProcess(ProjectId, ProcessId);
            ViewBag.ProjectName = ProjectServices.GetProjectNameById(ProjectId);
            var newprocess = ProjectServices.GetNewestProcess(ProjectId);
            return View(newprocess);
        }
        #endregion

        #region Join Request


        [HttpPost]
        public ActionResult JoinRequests(Guid id)
        {
            return Json(ProjectServices.GetProjectJoinRequets(id), JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public ActionResult Join(Guid Id, string Message)
        {
            MessageServices.SendProjectJoinMessage(HttpContext.User.Identity.Name, Id,Message);
            ProjectJoinRequest request = new ProjectJoinRequest
            {
                UserName = HttpContext.User.Identity.Name,
                Message = Message
            };
            ProjectServices.AddJoinRequest(Id, request);
            return Json(new { Result = "Ok" });
        }

        public ActionResult Quit(Guid id)
        {
            if (!ProjectServices.IsUserAdminOfProject(HttpContext.User.Identity.Name,id))
            {
                if ( IsUserInProject(id))
                {   
                    ProjectServices.RemoveMember(HttpContext.User.Identity.Name, id);
                    UpdateCache_IsUserInProject(HttpContext.User.Identity.Name, id, false);
                    return Json("退出成功", JsonRequestBehavior.AllowGet);
                }
                else
                    return Json("退出失败 - 用户不在项目中", JsonRequestBehavior.AllowGet);
            }
            else
            {
                return Json("退出失败 - 管理员无法退出，请先重新任命管理员", JsonRequestBehavior.AllowGet);
            }
        }


        [HttpPost]
        public ActionResult RequestApprove(string username, Guid projectid,Guid requestid)
        {
            if (string.IsNullOrEmpty(username)) throw new ArgumentException("username 不可以为空或null");
            if (GetProjectAdmin(projectid) == HttpContext.User.Identity.Name)
            {
                if (!IsUserInProject(username, projectid))
                {
                    ProjectServices.AddMember(username, projectid);
                    ProjectServices.RemoveJoinRequest(requestid);
                    UpdateCache_IsUserInProject(username, projectid, true);
                    var projectName = ProjectServices.GetProjectNameById(projectid);
                    MessageServices.SendJoinRequestApproveMessage(username, projectName);
                    return Json(new { Message = "加入成功", State = "Succeed" });
                }
                else
                    return Json(new { Message = "用户已经在项目中", State = "Failure" });
            }
            else
            {
                return Json(new { Message = "权限不足，只有管理员可以进行此操作", State = "Failure" });
            }
        }
        [HttpPost]
        public ActionResult RequestReject(string username, Guid projectid, Guid requestid)
        {
            if (string.IsNullOrEmpty(username)) throw new ArgumentException("username 不可以为空或null");
            if (GetProjectAdmin(projectid) == HttpContext.User.Identity.Name)
            {
                var projectName = ProjectServices.GetProjectNameById(projectid);
                ProjectServices.RemoveJoinRequest(requestid);
                MessageServices.SendJoinRequestRejectMessage(username, projectName);
                return Json(new { Message = "拒绝成功", State = "Succeed" });
            }
            else
            {
                return Json(new { Message = "权限不足", State = "Failure" });
            }
        }

        #endregion

        #region Appoint Admin
        [HttpPost]
        public ActionResult AppointAdmin()
        {
            Guid id = Guid.Parse(Request.Form["projectid"]);
            string username = Request.Form["username"];
            if (username == HttpContext.User.Identity.Name)
                return Json(new { Message = "操作无效-无法任命自己为管理员", State = "Failure" });
            if (GetProjectAdmin(id) == HttpContext.User.Identity.Name)
            {

                if (IsUserInProject(username, id))
                {
                    try
                    {
                        ProjectServices.ReAppointAdmin(username, id);
                        UpdateCache_ProjectAdmin(username, id);
                        return Json(new AjaxResponse{ Message = "任命成功", State = "Succeed" });
                    }
                    catch (Exception e)
                    {
                        return Json(new AjaxResponse { Message = "任命失败-" + e.Message, State = "Failure" });
                    }
                }
                else
                {
                    return Json(new AjaxResponse { Message = "任命失败-只可以任命项目组成员", State = "Failure" });
                }
            }
            else
            {
                return Json(new AjaxResponse { Message = "任命失败-只有管理员可进行此操作", State = "Failure" });
            }
        }
        #endregion

        #region cache

        private string GetProjectAdmin(Guid Id)
        {
            var index = Id.ToString() + "#@admin";
            if (HttpContext.Cache[index] == null)
            {
                HttpContext.Cache[index] = ProjectServices.GetAdminName(Id);
            }
            return (string)HttpContext.Cache[index];
        }
        private void UpdateCache_ProjectAdmin(string admin ,Guid id)
        {
            var index = id.ToString() + "#@admin";
            HttpContext.Cache[index] = admin;
        }
        private void UpdateCache_IsUserInProject(string username, Guid projectid, bool b)
        {
            var index = projectid.ToString() + username;
            if (HttpContext.Cache[index] != null)
            {
                HttpContext.Cache[index] = b;
            }
        }

        private bool IsUserInProject(string username, Guid Id)
        {
            var index = Id.ToString() + username;
            if (HttpContext.Cache[index] == null)
            {
                HttpContext.Cache[index] = ProjectServices.IsUserInProject(username, Id);
            }
            return (bool)HttpContext.Cache[index];
        }
        private bool IsUserInProject(Guid Id)
        {
            return IsUserInProject(HttpContext.User.Identity.Name, Id);
        }

        #endregion


        private void Init(Guid id)
        {
            ViewBag.HasJoined = IsUserInProject(id);
            ViewBag.ProjectId = id;
            ViewBag.Admin = GetProjectAdmin(id);
            ViewBag.IsAdmin = ViewBag.Admin == HttpContext.User.Identity.Name;
        }
    }



}
